using System.Security.Claims;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using iOSClub.WebAPI.Models.Users;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authorization;

namespace iOSClub.WebAPI.Controllers.Member;

[Route("api/[controller]/[action]")]
[ApiController]
public class MemberController : ControllerBase
{
    private readonly JwtHelper _jwtHelper;
    private readonly MemberContext _context;
    private readonly IHttpContextAccessor _httpContextAccessor;

    public MemberController(MemberContext context, JwtHelper jwtHelper,IHttpContextAccessor httpContextAccessor)

    {
        _context = context;
        _jwtHelper = jwtHelper;
        _httpContextAccessor = httpContextAccessor;
    }

    #region Visitor

    [HttpPost]
    public async Task<ActionResult<MemberModel>> SignUp(SignUpModel model)
    {
        
        if (DateTime.Today.Month != 10)
            return NotFound();

        if (_context.Students == null!)
        {
            return Problem("Entity set 'MemberContext.Students'  is null.");
        }

        var s = new MemberModel(model);

        _context.Students.Add(s);
        try
        {
            await _context.SaveChangesAsync();
        }
        catch (DbUpdateException)
        {
            if (await MemberModelExists(s.Id))
                return Conflict();

            throw;
        }

        return s;
    }


    [HttpPost]
    public async Task<ActionResult<MemberModel>> Login(LoginModel loginModel)
    {
        if (_context.Students == null!)
            return NotFound();

        var m = await _context.Students.FirstOrDefaultAsync(x => x.Id == loginModel.Id);

        if (m == null) return NotFound();

        return m;
    }

    #endregion

    #region Ordinary Members

    // PUT: api/Member/5
    [TokenActionFilter]
    [Authorize]
    [HttpPut("{id}")]
    public async Task<IActionResult> Update(string id, MemberModel memberModel)
    {
        if (id != memberModel.Id && !await MemberModelExists())
        {
            return BadRequest();
        }

        _context.Entry(memberModel).State = EntityState.Modified;

        try
        {
            await _context.SaveChangesAsync();
        }
        catch (DbUpdateConcurrencyException)
        {
            if (!await MemberModelExists(id))
                return NotFound();

            throw;
        }

        return NoContent();
    }

    [TokenActionFilter]
    [Authorize]
    [HttpDelete("{id}")]
    public async Task<IActionResult> Delete(string id)
    {
        if (DateTime.Today.Month != 6)
            return NotFound();

        if (_context.Students == null! || !await MemberModelExists())
            return NotFound();

        var memberModel = await _context.Students.FindAsync(id);

        if (memberModel == null)
            return NotFound();

        _context.Students.Remove(memberModel);
        await _context.SaveChangesAsync();

        return NoContent();
    }

    #endregion

    #region AddAuthentication

    [HttpPost]
    public async Task<ActionResult<string>> GetToken(MemberModel model)
    {
        if (_context.Students == null!)
            return NotFound();

        if (!await _context.Students.AnyAsync(x => x == model))
            return NotFound();

        return _jwtHelper.GetMemberToken(model);
    }

    private async Task GetCookie(MemberModel model)
    {
        var claims = new List<Claim>
        {
            new(ClaimTypes.Name, model.UserName),
            new(ClaimTypes.Role, model.Identity),
        };

        var claimsIdentity = new ClaimsIdentity(
            claims, CookieAuthenticationDefaults.AuthenticationScheme);

        var authProperties = new AuthenticationProperties
        {
            /*
            允许刷新 = <bool>，
            应允许刷新身份验证会话。

            ExpiresUtc = DateTimeOffset.UtcNow.AddMinutes（10），
            身份验证票证过期的时间。一个
            此处设置的值将覆盖 的 ExpireTimeSpan 选项
            CookieAuthenticationOptions使用AddCookie设置。

            持久 = 真，
            身份验证会话是否持久化
            多个请求。当与 Cookie 一起使用时，控件
            Cookie 的生存期是否绝对（匹配
            身份验证票证的生存期）或基于会话。

            已发行的 UTC = <DateTimeOffset>，
            发出身份验证票证的时间。

            重定向 = <string>
            要用作 http 的完整路径或绝对 URI
            重定向响应值。
             */
        };

        await HttpContext.SignInAsync(
            CookieAuthenticationDefaults.AuthenticationScheme,
            new ClaimsPrincipal(claimsIdentity),
            authProperties);
    }

    #endregion

    private async Task<bool> MemberModelExists(string id)
    {
        return await _context.Students?.AnyAsync(e => e.Id == id)!;
    }

    private async Task<bool> MemberModelExists()
    {
        var member = _httpContextAccessor.HttpContext?.User.GetUser();
        if (member is null) return false;
        return await _context.Students?.AnyAsync(x =>
            x.Id == member.Id && x.UserName == member.UserName && x.Identity == member.Identity)!;
    }
}